package com.allwees.bs.c.module.order.chain.create.handler;


import com.allwees.bs.c.module.order.chain.create.request.OrderCreateRequest;
import com.allwees.bs.c.module.order.chain.create.request.OrderItemCreateRequest;
import com.allwees.bs.c.module.product.dao.SkuDao;
import com.allwees.bs.c.module.product.entity.ProductEntity;
import com.allwees.bs.c.module.product.entity.SkuEntity;
import com.allwees.bs.c.module.product.repository.ProductRepository;
import com.allwees.bs.c.module.user.entity.UserCashEntity;
import com.allwees.bs.c.module.user.entity.UserCouponEntity;
import com.allwees.bs.c.module.user.entity.UserPromoLogEntity;
import com.allwees.bs.c.module.user.repository.UserCashRepository;
import com.allwees.bs.c.module.user.repository.UserCouponRepository;
import com.allwees.bs.c.module.user.repository.UserPromoLogRepository;
import com.allwees.bs.core.model.constant.CacheName;
import com.allwees.bs.core.modelbase.constant.ErrorMessage;
import com.allwees.bs.core.modelbase.constant.ResultCode;
import com.allwees.bs.core.modelbase.constant.ResultEnum;
import com.allwees.bs.core.modelbase.exception.BusinessException;
import com.allwees.core.cache.RedisUtil;
import com.allwees.core.common.constant.EStatus;
import com.allwees.core.common.context.AbstractHandler;
import com.allwees.core.common.util.MoneyUtil;
import com.allwees.support.marketing.handler.PriceAdjustor;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class OrderCreatePrepareHandler extends AbstractHandler<OrderCreateRequest> {

    @Autowired
    private ProductRepository productRepository;
    @Resource
    private SkuDao skuDao;
    @Autowired
    private UserCouponRepository userCouponRepository;
    @Autowired
    private UserCashRepository userCashRepository;
    @Autowired
    private UserPromoLogRepository userPromoLogRepository;


    @Override
    public OrderCreateRequest handler(OrderCreateRequest request) {

        validate(request.getUserUuid(), request.getAmtCash());

        validate(request.getUserUuid(), request.getUserCouponUuid(), request.getUserPromoLogUuid());


        Map<String, OrderItemCreateRequest> itemMap = request.itemMapBySkuUuid();

        List<SkuEntity> skus = skuDao.findByUuids(itemMap.keySet());
        //校验库存
        validateInventory(itemMap, skus);


        validate(skus);
        //调价
        PriceAdjustor.adjustPrice(skus);


        List<ProductEntity> products = productRepository.getByUuids(skus.stream().map(SkuEntity::getProductUuid).collect(Collectors.toSet()));
        validate(products);
        //校验限购次数
        validateBuyProductLimit(request.getUserUuid(), products, skus, itemMap);

        Map<String, SkuEntity> skuMap = skus.stream().collect(Collectors.toMap(SkuEntity::getUuid, o -> o));
        Map<String, ProductEntity> productMap = products.stream().collect(Collectors.toMap(ProductEntity::getUuid, o -> o));

        itemMap.forEach((skuUUid, item) -> {
            SkuEntity sku = skuMap.get(skuUUid);
            validate(sku);

            ProductEntity product = productMap.get(sku.getProductUuid());
            validate(product);

            setSkuRelevant(item, sku);
            setProductRelevant(item, product);
        });

        return doNext(request);
    }


    private void setSkuRelevant(OrderItemCreateRequest item, SkuEntity sku) {
        item.setSkuUuid(sku.getUuid());
        item.setSkuNo(sku.getValidNo());
        item.setPhotosStr(sku.getPhotosStr());
        item.setSkuColor(sku.getColor());
        item.setSkuSize(sku.getSize());
        item.setPrice(sku.getRetailPrice());//原价
        item.setOriginalPrice(sku.getRetailPrice());//原价
        item.setPriceAdjust(sku.getPriceRetail());//加价后售价
        item.setShippingPrice(sku.getShippingPrice());
        item.setShippingPriceAdjust(sku.getPriceShip());//加价后运费
        item.setSkuShippingCurrency(sku.getShippingCurrency());
    }

    private void setProductRelevant(OrderItemCreateRequest item, ProductEntity product) {
        item.setSupplierUuid(product.getSupplierUuid());
        item.setRetailerUuid(product.getRetailerUuid());
        item.setStoreUuid(product.getStoreUuid());

        item.setProductUuid(product.getUuid());
        item.setProductNo(product.getValidNo());
        item.setProductName(product.getName());
        item.setProductPhoto(product.getMainPhoto());
        item.setProductDesc(product.getDescription());
        item.setDefNo(product.getDefNo());
        item.setCategoryNo(product.getCategoryNo());
        item.setProductShippingArrivalDesc(product.getShippingArrivalDesc());
        item.setCurrency(product.getCurrency());
        item.setFreeGift(product.isFreeGift());
    }

    /**
     * 校验限购次数
     *
     * @param userUuid
     * @param products
     * @param skus
     * @param requestMap
     */
    private void validateBuyProductLimit(String userUuid, List<ProductEntity> products, List<SkuEntity> skus, Map<String, OrderItemCreateRequest> requestMap) {
        for (ProductEntity product : products) {
            if (product.getNumPerUser() == null || product.getNumPerUser() == 0) {
                continue;
            }
            Integer buyedNum = RedisUtil.hget(CacheName.USER_BUY_PRODUCT_NUM, userUuid + ":" + product.getUuid());
            log.info("======checkout=======userUuid:{},has buyed num:{}, productUuid:{}", userUuid, buyedNum, product.getUuid());
            if (buyedNum == null) {
                buyedNum = 0;
            }
            Integer totalNum = 0;
            for (SkuEntity sku : skus) {
                if (sku.getProductUuid().equals(product.getUuid())) {
                    totalNum += requestMap.get(sku.getUuid()).getQuantity();
                }
            }
            if ((totalNum + buyedNum) > product.getNumPerUser()) {
                String[] productNameArr = product.getName().split(" ");
                if (productNameArr.length >= 2) {
                    throw BusinessException.getInstance(ResultEnum.PRODUCT_LIMIT_CHECKOUT,
                            new Object[]{productNameArr[0] + " " + productNameArr[1] + "...",
                                    String.valueOf(product.getNumPerUser())});
                } else {
                    throw BusinessException.getInstance(ResultEnum.PRODUCT_LIMIT_CHECKOUT,
                            new Object[]{"", String.valueOf(product.getNumPerUser())});
                }

            }
        }
    }

    private void validateInventory(Map<String, OrderItemCreateRequest> requestMap, List<SkuEntity> skus) {
        for (SkuEntity sku : skus) {
            if (requestMap.get(sku.getUuid()).getQuantity().compareTo(sku.getQuantity()) > 0) {
                throw BusinessException.getInstance(ResultEnum.NO_STOCK_ERROR);
            }
        }
    }

    /**
     * 验证现金是否大于商品金额
     *
     * @param userUuid
     * @param amtCash
     */
    private void validate(String userUuid, BigDecimal amtCash) {
        if (MoneyUtil.isNullOrZero(amtCash)) {
            return;
        }
        UserCashEntity userCash = userCashRepository.findByUserUuid(userUuid);

        if (userCash == null || userCash.getValue() == null || userCash.getValue().compareTo(amtCash) < 0) {
            throw BusinessException.getInstance(ResultEnum.USER_CASH_INSUFFICIENT);
        }
    }

    /**
     * 校验coupon和promo code log
     *
     * @param userUuid
     * @param couponDefUuid
     * @param userPromoLogUuid
     */
    private void validate(String userUuid, String couponDefUuid, String userPromoLogUuid) {
        if (StringUtils.isNotBlank(couponDefUuid)) {
            validateCouponDefUuid(userUuid, couponDefUuid);
        }

        if (StringUtils.isNotBlank(userPromoLogUuid)) {
            validateUserPromoLogUuid(userUuid, userPromoLogUuid);
        }
    }

    private void validateCouponDefUuid(String userUuid, String couponDefUuid) {
        UserCouponEntity userCoupon = userCouponRepository.getByUuid(couponDefUuid);
        if (userCoupon == null || !userCoupon.getUserUuid().equals(userUuid)) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
        if (!EStatus.USED.equals(userCoupon.getEStatus())) {
            throw BusinessException.getInstance(ResultEnum.USER_COUPON_USED);
        }
    }

    private void validateUserPromoLogUuid(String userUuid, String userPromoLogUuid) {
        UserPromoLogEntity userPromoLog = userPromoLogRepository.findByUuid(userPromoLogUuid);
        if (!userPromoLog.getUserUuid().equals(userUuid)) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
        if (!EStatus.NORMAL.equals(userPromoLog.getEStatus())) {
            throw BusinessException.getInstance(ResultEnum.USER_COUPON_USED);
        }
    }

    private void validate(List skus) {
        if (CollectionUtils.isEmpty(skus)) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
    }

    private void validate(Object obj) {
        if (obj == null) {
            throw BusinessException.getInstance(ResultEnum.NOT_FOUND);
        }
    }
}
